
declare global {
  interface Document {
    currentStyle: any;
  }
}

const DragDialog: import("vue").DirectiveOptions = {
  bind(el) {
    const dragDom = el.querySelector(".el-dialog") as HTMLDivElement;
    const dialogHeaderEl = el.querySelector(".el-dialog__header") as HTMLDivElement;


    dialogHeaderEl.style.cssText += `cursor:move;`;

    // 获取原有属性 ie dom元素.currentStyle 火狐谷歌 window.getComputedStyle(dom元素, null);
    const getStyle = (() => {
      if (window.document.currentStyle) {
        return (dom, attr) => dom.currentStyle[attr];
      } else {
        return (dom, attr) => getComputedStyle(dom)[attr];
      }
    })();

    dialogHeaderEl.onmousedown = e => {
      dragDom.style.cssText += `;transition: none;opacity:0.5;`;// 拖动的时候禁止过渡效果

      const screenWidth = document.body.clientWidth;
      const screenHeight = document.body.clientHeight;

      // 鼠标按下，计算当前元素距离可视区的距离
      const disX = e.clientX - dialogHeaderEl.offsetLeft;
      const disY = e.clientY - dialogHeaderEl.offsetTop;

      const dragDomWidth = dragDom.offsetWidth;
      const dragDomHeight = dragDom.offsetHeight;

      const minDragDomLeft = dragDom.offsetLeft;
      const maxDragDomLeft = screenWidth - dragDom.offsetLeft - dragDomWidth - 1; // 扣除1px 的偏差，防止移动到最右边时候出现滚动条

      const minDragDomTop = dragDom.offsetTop;
      const maxDragDomTop = screenHeight - dragDom.offsetTop - dragDomHeight - 1; // 扣除1px 的偏差，防止移动到最下边时候出现滚动条
      console.log("maxDragDomLeft", maxDragDomLeft);
      // 获取到的值带px 正则匹配替换
      let styL = getStyle(dragDom, "left");
      let styT = getStyle(dragDom, "top");

      if (styL.includes("%")) {
        styL = Number(screenWidth) * (Number(styL.replace(/\%/g, "")) / 100);
        styT = Number(screenHeight) * (Number(styT.replace(/\%/g, "")) / 100);
      } else {
        styL = Number(styL.replace(/\px/g, ""));
        styT = Number(styT.replace(/\px/g, ""));
      }

      const onMouseMove = e => {
      // const {x, y} = (e.target as any).getBoundingClientRect();
      // 通过事件委托，计算移动的距离
        let left = e.clientX - disX;
        let top = e.clientY - disY;
        // let left = x - disX;
        // let top = y - disY;

        // 边界处理
        if (-left > minDragDomLeft) {
          left = -minDragDomLeft;
        } else if (left > maxDragDomLeft) {
          left = maxDragDomLeft;
        }

        if (-top > minDragDomTop) {
          top = -minDragDomTop;
        } else if (top > maxDragDomTop) {
          top = maxDragDomTop;
        }

        // 移动当前元素
        //! 使用百分比，方式窗口跑到视窗外面，等比例自动 适应
        dragDom.style.cssText += `;left:${left + styL}px;top:${top + styT}px`;
      // console.log("move", left);
      // emit onDrag event
      // vnode.child.$emit("dragDialog");
      };
      const onMouseUp = () => {
        dragDom.style.cssText += `;opacity:1;`;

        window.removeEventListener("mousemove", onMouseMove);
        window.removeEventListener("mouseup", onMouseUp);
      };

      window.addEventListener("mousemove", onMouseMove, false);
      window.addEventListener("mouseup", onMouseUp, false);

    };

  },
  update(el, binding, vnode, oldVnode) {
    // 首次触发时候，visible为true,但还没完全显示出来，所以会调用两次update
    if ((vnode.componentOptions.propsData as any).visible ) {
      const dragDom = el.querySelector(".el-dialog") as HTMLDivElement;
      if (oldVnode && !(oldVnode.componentOptions.propsData as any).visible) {
        //! 首次显示时还原，防止位置被记住
        const width = dragDom.style.width;
        dragDom.style.cssText = `width:${width}`;
      } else if ((vnode.componentInstance as any).opened) {
        // 必须在下一次事件循环中执行，否则获取到的值不正确
        vnode.componentInstance.$nextTick(() => {
          //! 由于可能存在 transform 位移，所以真实的坐标通过下面的代码来获取更为精准，为鼠标按下的时候进行位置修复
          //  这个时候已经进入将dialog 显示出来了
          // 将left,top 数据设置出来预设为初始位置，去除transform值
          const {x, y} = dragDom.getBoundingClientRect();
          dragDom.style.cssText += `left:${x}px;top:${y}px;transform:none`;
        });
        // 判断如果存在__whenWinowResize__ 值，说明绑定过了
        if (!(el as any).__whenWinowResize__) {
          let screenWidth = document.body.clientWidth;
          let screenHeight = document.body.clientHeight;

          let resizeTimer: ReturnType<typeof setTimeout>;
          const time = 50;
          const whenWinowResize = () => {
          // 通过计时器达到 N 毫秒内只会执行一次
            if (resizeTimer) {
              clearTimeout(resizeTimer);
            }

            resizeTimer = setTimeout(() => {
              const {x, y, width, height} = dragDom.getBoundingClientRect();

              const styL = x / (screenWidth - width) * (document.body.clientWidth - width);
              const styT = y / (screenHeight - height) * (document.body.clientHeight - height);
              // 更新缓存的文档宽高
              screenWidth = document.body.clientWidth;
              screenHeight = document.body.clientHeight;

              dragDom.style.cssText += `;left:${styL}px;top:${styT}px;transition: all 0.1s;`;

            }, time);
          };
          window.addEventListener("resize", whenWinowResize);
          (el as any).__whenWinowResize__ = whenWinowResize;
        }
      }
    }
  },
  unbind(el) {
    window.removeEventListener("resize", (el as any).__whenWinowResize__ );
  },
};

export default DragDialog;
